# coding:utf-8
# writingtime: 2022-6-28
# author: wanjun
'''
二维图：对算子的q值分析图,与其他算子比较生成多子图，雷达图
'''
import base64
import os.path
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from collections import Counter
from io import BytesIO
colors = ['brown', 'orange', 'purple', 'olive', 'gray', 'pink', 'black', 'red', 'green', 'blue', 'cyan', 'm'
    , 'yellow', 'crimson', 'skyblue', 'teal', 'peru', 'tomato', 'wheat', 'darkgreen', 'lime']
markers = ['o', 's', 'd', 'p', 'h', 'x', 'v', '<', '.', '1', '*', '+', ',', '^', '>', '1', '2', '3', '4', '8', 'P', 'H']


def matrixReverse(matrix):
    '''
    function: 功能函数
    :param matrix: 矩阵
    :return: 行列交换的矩阵
    '''
    newMatrix = []
    for x in range(len(matrix[0])):
        temp = []
        for y in range(len(matrix)):
            temp.append(matrix[y][x])
        newMatrix.append(temp)

    return newMatrix


class SimpleClass:
    def __init__(self):
        self.img2D = ""  # 返回的2D图
        self.imgRadar="" #返回的雷达图
    def qSensitivity(self, value_matrix, q_list, x_label='Q', y_label='Value',
                     title='title', filename='test.png', marksize=5,label_list=None,
                     y_ticks=None, imgShow=True, imgSaving=False):
        '''
        function: 对算子的q值进行分析所作的图,
        :param value_matrix: 不同的q下，不同的方案组得分，一个矩阵
        :param q_list: q的取值列表
        :param x_label: x轴的标签
        :param y_label: y轴的标签
        :param filename: 文件名
        :param y_ticks: y轴的刻度
        :param imgShow: 是否展示结果
        :param imgSaving: 是否保存结果
        :param marksize: 标记的大小
        :param label_list: 标签名称
        :return:
        '''
        plan_quanatity = len(value_matrix)  # 方案的个数
        if label_list is None:
            label_list=['x%s' % (i + 1) for i in range(plan_quanatity)]
        fig, ax = plt.subplots(figsize=(12.5, 7.2))
        plt.xlabel(x_label)
        plt.ylabel(y_label)
        plt.title(title)
        for i in range(plan_quanatity):
            ax.plot(q_list, value_matrix[i], label=label_list[i], color=colors[i], marker=markers[i], linewidth=1,
                    ms=marksize)
        if y_ticks is not None:
            plt.yticks(y_ticks)
        ax.grid()  # 显示网格
        plt.legend(bbox_to_anchor=(1.10, 1.09))  # 显示标签

        #转成图片的步骤
        sio = BytesIO()
        plt.savefig(sio,format='png')
        data = base64.encodebytes(sio.getvalue()).decode()
        self.img2D = data
        if imgSaving:
            plt.savefig(filename)  # 保存图片
            print(filename, 'is saved')
        if imgShow:
            plt.show()  # 显示图片
        plt.close()
        return data

    def aid_plot(self, ax, x_list, y_list, title='Title', y_label='value', x_label='Q'):
        '''
        function: 辅助OpSensitivity画图工具
        :param ax: 图
        :param x_list: x轴上的值
        :param y_list: y的值
        :param title: 标题
        :param y_label: y轴名称
        :param x_label: x轴名称
        :return: null
        '''

        ax.set_xlabel(x_label, fontsize=12)
        ax.set_ylabel(y_label, fontsize=12)
        ax.set_title(title, fontsize=14)

        for i in range(len(y_list)):
            ax.plot(x_list, y_list[i], label='x%s' % (i + 1), color=colors[i], marker=markers[i], linewidth=1, ms=5)
        plt.legend(bbox_to_anchor=(1.11, 1.089), fontsize='small')  # 显示标签
        ax.grid()  # 显示网格线

    def opSensitivity(self, value_gruop, q_list, title_list, filename='test.png', imgShow=True, imgSaving=False):
        '''

        :param value_gruop: 结果群
        :param q_list: q的范围
        :param title_list:
        :param filename:
        :param imgShow:
        :param imgSaving:
        :return:
        '''
        re = len(value_gruop) % 4
        if re:
            fig_numb = int(len(value_gruop) / 4) + 1
        else:
            fig_numb = int(len(value_gruop) / 4)

        flag = 0

        for i in range(fig_numb):
            # 绘制2x2的子图
            if i != fig_numb - 1 or re == 0:
                fig = plt.figure(constrained_layout=False, figsize=(12.5, 7.2))
                gs0 = gridspec.GridSpec(2, 1, figure=fig)
                gs1 = gridspec.GridSpecFromSubplotSpec(1, 2, subplot_spec=gs0[0])
                for n in range(2):
                    ax = fig.add_subplot(gs1[n])
                    self.aid_plot(ax, q_list, value_gruop[flag], title=title_list[flag])
                    flag += 1
                gs2 = gridspec.GridSpecFromSubplotSpec(1, 2, subplot_spec=gs0[1])
                for n in range(2):
                    ax = fig.add_subplot(gs2[n])
                    self.aid_plot(ax, q_list, value_gruop[flag], title=title_list[flag])
                    flag += 1
            else:
                fig = plt.figure(constrained_layout=False, figsize=(12.5, 7.2))
                gs = {
                    3: gridspec.GridSpec(1, 2, figure=fig),
                    2: gridspec.GridSpec(1, 2, figure=fig),
                    1: gridspec.GridSpec(1, 1, figure=fig)
                }
                gs0 = gs[re]
                if re == 3:
                    gs1 = gridspec.GridSpecFromSubplotSpec(2, 1, subplot_spec=gs0[0])
                    for n in range(2):
                        ax = fig.add_subplot(gs1[n])
                        self.aid_plot(ax, q_list, value_gruop[flag], title=title_list[flag])
                        flag += 1
                    gs2 = gridspec.GridSpecFromSubplotSpec(1, 1, subplot_spec=gs0[1])
                    for n in range(1):
                        ax = fig.add_subplot(gs2[n])
                        self.aid_plot(ax, q_list, value_gruop[flag], title=title_list[flag])
                        flag += 1
                elif re == 2:
                    gs1 = gridspec.GridSpecFromSubplotSpec(1, 1, subplot_spec=gs0[0])
                    for n in range(1):
                        ax = fig.add_subplot(gs1[n])
                        self.aid_plot(ax, q_list, value_gruop[flag], title=title_list[flag])
                        flag += 1

                    gs2 = gridspec.GridSpecFromSubplotSpec(1, 1, subplot_spec=gs0[1])
                    for n in range(1):
                        ax = fig.add_subplot(gs2[n])
                        self.aid_plot(ax, q_list, value_gruop[flag], title=title_list[flag])
                        flag += 1
                elif re == 1:
                    gs1 = gridspec.GridSpecFromSubplotSpec(1, 1, subplot_spec=gs0[0])
                    for n in range(1):
                        ax = fig.add_subplot(gs1[n])
                        self.aid_plot(ax, q_list, value_gruop[flag], title=title_list[flag])
                        flag += 1

            plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.2, hspace=0.3)
            filename = os.path.join(filename, '(%s)' % str(fig_numb) + 'result.png')

            if imgSaving:
                plt.savefig(filename)  # 保存图片
                print(filename, 'is saved')
            if imgShow:
                plt.show()  # 显示图片
            plt.close()

    def radarPlot(self, value_matrix, name_list, filename='test.png', imgShow=True, imgSaving=False, title='Title'):
        '''
        function：雷达图，试用于多个算子对于一组数据计算得分的分析
        :param value_matrix: 数据矩阵，每个向量表示一个算子聚合结果
        :param name_list: 算子 名称列表
        :param title: 标题
        :param filename: 文件名称
        :param imgShow: 是否展示图片
        :param imgSaviong: 是否保存图片
        :return:
        '''
        # 算子的个数
        length = len(value_matrix)
        # 绘制图形类型
        fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}, figsize=(12.5, 7.2))
        # 标题
        plt.title(title)
        # 将极坐标根据数据长度进行等分
        data_r = np.linspace(0, 2 * np.pi, len(value_matrix[0]), endpoint=False)
        # 将极坐标闭环
        data_r = np.concatenate((data_r, [data_r[0]]))
        for i in range(length):
            temp = np.array(value_matrix[i])
            # 将数据闭环
            data_list = np.concatenate((temp, [temp[0]]))
            ax.plot(data_r, data_list, label='x%s' % (i + 1), color=colors[i], marker=markers[i], linewidth=1, ms=4)
        # 设置标签
        plt.legend(bbox_to_anchor=(1.15, 1.09))
        # 设置名称比钱显示
        name_list = np.array(name_list)
        name_list = np.concatenate((name_list, [name_list[0]]))
        ax.set_thetagrids(data_r * 180 / np.pi, name_list)
        # plt.set_ticks(name_list)
        # 设置雷达图的0度起始位置
        ax.set_theta_zero_location('N')
        # 设置雷达图的坐标刻度范围
        ax.set_rlim(-1, 1)
        # 雷达图显示的刻度
        ax.set_rticks([-1, -0.6, -0.2, 0.2, 0.6, 1])
        # 将径向标签移开
        ax.set_rlabel_position(-22.5)
        ax.grid(True)
        # 标题及其格式
        # ax.set_title(title, va='bottom')
        #转成图片的步骤
        sio = BytesIO()
        plt.savefig(sio,format='png')
        data = base64.encodebytes(sio.getvalue()).decode()
        self.imgRadar = data
        if imgShow:
            plt.show()
        if imgSaving:
            plt.savefig(filename)
            print(filename, 'is saved')
        plt.close()
        return data

    def rankPlan(self, value_matrix):
        '''
        function: 将结果排序
        :param value_matrix: 结果得分矩阵
        :return: 每个方案排名的数据集
        '''
        temp=[np.array(i) for i in value_matrix]
        result = [np.argsort(np.argsort(-i)) + 1 for i in temp]
        result = matrixReverse(result)
        return result

    def deviationPlot(self, value_matrix, planSum=None, planOrder=None, filename='test.png', imgShow=True, imgSaving=False):
        '''
        function: 显示偏差的图，一张4子图
        :param value_matrix: 值计算结果
        :param planOrder: 选取要展示的方案序号
        :param planSum: 总方案数
        :param filename: 保存的文件名
        :param imgShow: 是否显示图片
        :param imgSaving: 是否保存图片
        :return:
        '''
        if planOrder is None:
            planOrder = [1, 2, 3, 4]
        if planSum is None:
            planSum=10
        # 得到排序结果
        rank_matrix = self.rankPlan(value_matrix)
        # 选取4个方案的排序结果
        matrix4 = [rank_matrix[planOrder[0] - 1], rank_matrix[planOrder[1] - 1], rank_matrix[planOrder[2] - 1],
                   rank_matrix[planOrder[3] - 1]]
        # 构建子图
        flag = [[0, 0], [0, 1], [1, 0], [1, 1]]
        fig, axs = plt.subplots(2, 2, figsize=(12.5, 7.2))
        for f in range(4):
            # 获取方案排的最多的
            mostNumb = Counter(matrix4[f]).most_common(1)[0][0]
            # 将排名数据标准化
            temp = np.array(matrix4[f]) - mostNumb
            # 填数据到子图中
            error_range=np.array([np.array([0 for i in range(len(temp))]),temp])
            axs[flag[f][0], flag[f][1]].errorbar([i + 1 for i in range(len(temp))]
                                                 , [mostNumb for i in range(len(temp))], yerr=error_range,
                                                 color=colors[f], ecolor=colors[f], elinewidth=1, linewidth=1)
            # 设置子图标题
            axs[flag[f][0], flag[f][1]].set_title('The fluctuation of A{} in diffferent ranking positions'.format(planOrder[f]))
            # 设置y轴的名称
            axs[flag[f][0], flag[f][1]].set_ylabel('Ranking Positions')
            # 设置x轴的名称
            axs[flag[f][0], flag[f][1]].set_xlabel('Q')
            # 设置y轴的刻度
            axs[flag[f][0], flag[f][1]].set_ylim((0, planSum+1))
            # axs[flag[f][0], flag[f][1]].set_xlim((0.9, len(temp) + 0.1))
        plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.2, hspace=0.3)
        if imgShow:
            plt.show()
        if imgSaving:
            plt.savefig(filename)
            print(filename, 'is saved')
        plt.close()
    def getImg2D(self):
        return self.img2D
    def getImgRadar(self):
        return self.imgRadar

if __name__ == '__main__':
    li1 = [[0.676778370143161, -0.20171725871805501, -0.13991984907074997, -0.19424505181604002, 0.6632911793136638],
           [-0.47972900555291703, 0.22983968194465493, -0.09931693059271803, 0.04184085346295803, -0.334890248961605],
           [-0.177987602833097, -0.30001900968155204, -0.14172040624999993, 0.006726775056767997, 0.14256639065292798],
           [-0.29039809731808, 0.09993319266975798, 0.441332813046415, 0.06408330289599998, -0.16258631472311802],
           [0.6211129154477438, 0.14001375518044198, -0.134089663813456, 0.15761548412997395, -0.3467785359434761]]
    li2 = [[0.676778370143161, -0.20171725871805501, -0.13991984907074997, -0.19424505181604002, 0.6632911793136638],
           [-0.47972900555291703, 0.22983968194465493, -0.09931693059271803, 0.04184085346295803, -0.334890248961605],
           [-0.177987602833097, -0.30001900968155204, -0.14172040624999993, 0.006726775056767997, 0.14256639065292798],
           [-0.29039809731808, 0.09993319266975798, 0.441332813046415, 0.06408330289599998, -0.16258631472311802],
           [0.6211129154477438, 0.14001375518044198, -0.134089663813456, 0.15761548412997395, -0.3467785359434761],
           [0.676778370143161, -0.20171725871805501, -0.13991984907074997, -0.19424505181604002, 0.6632911793136638],
           [-0.47972900555291703, 0.22983968194465493, -0.09931693059271803, 0.04184085346295803, -0.334890248961605],
           [-0.177987602833097, -0.30001900968155204, -0.14172040624999993, 0.006726775056767997, 0.14256639065292798]
           ]
    li3 = [[-0.02386906396874998, 0.755770521112178, -0.053917654786754005, -0.0036360276480000148, -0.39291258544128],
           [0.45471213599167787, 0.167644792485625, -0.11191452864074997, -0.12808724735726595, -0.705328905686125],
           [-0.471508586764984, -0.13494840814902603, -0.259925952766329, 0.382493613993634, 0.5293814338602819],
           [-0.08359642452787201, -0.08099105757195202, 0.36077961664049807, -0.118141841729106, -0.04767854593041401],
           [0.2813505069943751, 0.316276999243127, 0.20918787076786502, -0.15675649595788005, 0.08948859494400001]]
    li4 = [[0.6929238059857401, -0.50043092, 0.9137740000000001, 0.37920816874707197, 0.684017277068488],
           [-0.032243295644765975, -0.5349114240575841, 0.5857553688643751, 0.8484250612603821, -0.7168901182995691],
           [0.36178815410500004, 0.5482271064253771, -0.05748167152880602, -0.05282151106728202, 0.18431700125093095],
           [-0.324939483153883, 0.709517648613087, -0.016046225296758032, -0.533418317318551, -0.24950382156543996],
           [0.14142282214678203, -0.11870023199783403, -0.10604110486775001, 0.10814175330914196, -0.5085137006038349]]
    li5 = [[-0.14676983423449597, -0.672844236790131, 0.5658573561036799, -0.020002599935999996, 0.47518530111499996],
           [-0.181229739224495, -0.022443646735281986, -0.052791065742478036, 0.08730854321454402, 0.17499351981535102],
           [-0.283372339923431, -0.26581849930115997, 0.11484047594764804, 0.004029937642192019, 0.31803735803757305],
           [-0.11519676211264598, -0.505876519584689, -0.06005722229363198, 0.09828497163481595, 0.13769855064531406],
           [0.021503564486117996, 0.010226865093749982, 0.5605366437408321, 0.39532361442347297, 0.108450804217262]]
    li2 = matrixReverse(li2)
    value_list = [li2, li2, li2, li2]
    xlist = [[0.1, 0.4, 0.2, 0.3], [0.3, 0.6, 0.3, 0.4]]
    ylist = [1, 2, 3, 4]
    # example=SimpleClass().qSensitivity(xlist,ylist)
    # example = SimpleClass().opSensitivity(value_list, [3, 4, 5, 6, 7, 8, 9, 10], ['A', 'WA', 'GA', 'AA'],imgSaving=False, imgShow=True)
    # example=SimpleClass().radarPlot(li3,['A','WA','GA','AA','OWA'],imgShow=True)
    # exmaple = SimpleClass().deviationPlot(li5)
